home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr48
/
file211.zip
/
FILEDEF.DOC
< prev
next >
Wrap
Text File
|
1993-04-07
|
12KB
|
232 lines
File Formats for Searchlight BBS (as of ver 2.11)
--------------------------------
Introduction
------------
This ZIPfile contains the data types for Searchlight BBS data files as of
version 2.11, released on 3/4/91. These data types should be considered
stable.
No executable code is being provided with this release of the data types.
This is primarily because the code necessary to access the data in
Searchlight 2.0 is complex, and a user oriented library needs to be
developed. I would not encourage authors to attempt to write code to access
Searchlight 2.0 subboards at this point: wait for a filedef release which
includes the code library. Access to the CONFIG file is much the same as in
version 1.x and should not be a problem at this point.
The data contained in these documents is only the tip of the iceberg. Below
is an overview of the general structure of Searchlight 2.0 data files which
outlines the similarities between them. Discussions of the individual data
files will be provided in future editions. As well, I plan to release some
code libraries, either as source or as Turbo Pascal units, for accessing
SLBBS files. Those who program in Pascal may want to wait for the release
of these tools before desigining major applications.
Searchlight 2.0 File Overview
-----------------------------
The Searchlight CONFIG, CHAT and NODES files operate much the same way as in
version 1.x, except for the addition and reorganization of the data fields.
NODES.SL2 is the same file as SYSTEM.BBS in previous versions.
There is a major difference between the way Searchlight 2.0 handles its
other data files as compared to all previous versions of SLBBS. If you plan
to do any work with SLBBS beyond reading the CONFIG file, it is vitally
important that you read, and understand, the following discussion.
Previous versions of Searchlight used a standard "File Of Type" approach to
all of its data files. That is, each data file was declared in the Pascal
source code as a file of some record type; for example:
Var userfile: file of usertype;
Physically, the disk image of each Searchlight 1.x file consists of any
number of uniform records, each the same size and type.
This is emphatically NOT the case with Searchlight 2.0. All SLBBS data
files, with the exception of the CONFIG, CHAT and NODES files, are declared
as "file of byte" within the Searchlight source code. In actuality, each
data file is, for the most part, composed of fixed size records, but there
are various data fields placed at the beginning of each file which do not
conform to the size or type of the records that make up the bulk of the
file.
Before I continue, a word about why this file format was developed may be
helpful. In the course of designing Searchlight 1.x, I noticed that
different files, such as the USER, MESSAGE and DIR files, had two things in
common. The first is that each file consists of records, and requires that
records be allocated, deleted, and reused. The second common feature of
these files is that while they consist of fixed size records, certain
variable information is associated with each file-- such as the number of
users in the user file. In Searchlight 1.x, essentially the same code to
allocate and delete records from these data files had to be rewritten
specifically for each file. The various "extra" pieces of information for
each file were tucked in unused fields wherever these could be found.
The first part of writing Searchlight 2.0 was to design a universal file
management scheme that could handle the basic file maintenance chores of any
data file, thus greatly reducing the amount of effort I would need to create
new files. The result is a general file library that underlies all of
Searchlight's block-oriented files; I call this the Block File manager.
Searchlight's block file manager divides each file into three parts:
(1) A Standard Header part. This is a fixed size record (defined as
FileHeader in BLOCK.PAS) which contains the sizes in bytes of the
variable header and data records, as well as a pointer to the next
free data record.
(2) A Variable Header part. This is any number of bytes containing any
general "header" information required by the file.
(3) Data blocks. Any number of data records associated with the file;
the size of each record is defined in the standard header.
Searchlight 2.0 also uses standard procedures to maintain its binary tree
indexes (user, setup, member and DIR files). The index information is
defined in BLOCK.PAS.
The User File: An Example
-------------------------
The Searchlight user file is divided into three parts, as per the block file
manager. First is the standard header (FileHeader); followed by the user
file header (UserHeader); then the individual user records (UserType). The
first data record of all Searchlight files is always referred to as record 1.
Here is the general procedure you'd use to access the user file:
(1) Open the file as a FILE OF BYTE. Example:
var userfile: file of byte;
...
assign(userfile,'USER.SL2');
reset(userfile,1);
(2) Read the FileHeader, which is always the first information in the file:
var header: fileheader;
...
seek(userfile,0);
blockread(userfile,header,sizeof(header));
(3) The "Header" record now tells you the size of each user record, as well
as the offset in the file to record 1. The data between the start of
record 1 and the end of the standard header is the UserHeader data.
Here is an example of how to read the UserHeader:
var h: userheader;
...
seek(userfile,sizeof(fileheader));
blockread(userfile,h,sizeof(h));
(4) Here is an example of how to read any arbitrary record from the user
file, assuming "N" is the record number you want to read (N should be of
type longint):
var user: usertype;
...
seek(userfile,(sizeof(user)*(n-1))+sizeof(fileheader)+sizeof(userheader));
blockread(userfile,user,sizeof(user));
These examples use the SIZEOF function to obtain the sizes of the data
records being retrieved; however, you can also get this information from the
FileHeader data at the top of the file. FileHeader.RecSize contains the
size of the data blocks in the file (in this case, the same as sizeof(user))
and FileHeader.Offset contains the offset to the first block of data past
the header information (in this case, equal to sizeof(fileheader)+sizeof
(userheader)). Thus, assuming the variable "header" contains the fileheader
information read in step (2) above, step (4) could be rewritten as:
seek(userfile,(header.recsize*(n-1))+header.offset);
blockread(userfile,user,header.recsize);
Why is this important? Because it applies to ALL Searchlight data files
including the subboard header, text and member files; the DIR files; the
Setup files (SUBBOARD.SL2, FILEDIR.SL2); and even the Quotes file. The
block definition provides a universal way to access data in any of these
files, so that the same procedures can operate on all of them without
knowing the data types involved.
The RecordHeader Type
---------------------
RecordHeader (defined in BLOCK.PAS) is a data type which is superimposed
(typecast) onto the data records in Searchlight files for the purpose of
maintaining a list of free records. Although the type definition Record-
Header doesn't appear as part of the data records in FILEDIR.DEF, the block
file manager writes records of this type on top of the actual data in the
file records when it deletes a record from the file. Since the record is
being deleted, it doesn't really matter that its data is overwritten.
RecordHeader contains the following fields:
RecordHeader = record { control header to records }
mark: byte; { FF to indicate deleted rec }
extra: byte;
next: longint; { ptr to next free rec }
end;
MARK is set to a value of 255 ($FF) to indicate that the record is deleted.
This helps programs that process files sequentially identify and skip
deleted records. The data files in Searchlight always reserve the first
byte of each record in order to accomodate the $FF mark without the
possibility of overwriting it. The subboard message (MSG) files use the
mark byte as a counter to indicate the number of copies of a record that are
currently in use (additional copies of a text record are created when
mail is sent to more than one recipient).
The NEXT pointer points to the next free record on the list: and the first
free record on the list is pointed to by the "NextFree" pointer in the
FileHeader. The way to ALLOCATE a record in any Searchlight file is to take
the first free record pointed to by NextFree off of the linked list by
pointing NextFree to the NEXT value in the first free record. If there are
no free records (NextFree=0) then the file must be physically expanded. The
way to DELETE any record in a Searchlight file is to add it to the free
record list (inserting it at the top of the list is most efficient).
The TreeRoot and TreeLeaf types
-------------------------------
These data types, declared in BLOCK.PAS, define the binary tree structure
used by Searchlight's user, member, Setup and DIR files. Additionally, the
linked list type (used by the Files program to store files by date) is
defined as part of these structures.
TreeRootType = record { root info for tree/list type files }
treeroot: longint; { root of tree }
listroot: longint; { linked list root }
entries: longint; { # of entries }
end;
TreeLeafType = record { leaf info for tree/list type files }
status: byte; { 0=active, 255=deleted }
left,right: longint; { pointers to child nodes }
last,next: longint; { linked list ptrs }
end;
Files which use the binary tree index have a TreeRootType declared as the
FIRST element in their file headers (the first data after the standard
FileHeader information) and have a TreeLeafType declared as the FIRST
element of each data record. Notice that the first byte of TreeLeafType is
a byte called status; since TreeLeafType is the first data in each record,
the first byte of it overlays the first byte of RecordHeader. Therefore,
the value TreeLeafType.status can be compared to 255 ($FF) to determine
whether a record is active or deleted.
To traverse the binary tree, start with the TreeRootType.treeroot value
(which indicates the record number of the first entry). Then follow the
TreeLeafType.left and TreeLeafType.right pointers to the records. Remember
that each of these pointers is a longint value which represents the record
number of the pointed to data. In order to retrieve the record, use a
formula such as the one shown in part (4) of the user file example above.
To follow the date sorted list (in file DIR files), start with listroot and
follow the TreeLeaf.next pointers forward. Since the first entry on the
linked list is the most recent file, "forward" actually means backward in
time. TreeLeaf.last can be used to follow the list backward if desired.